package cn.iocoder.yudao.module.scrm.service.customer.customerrepository;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.redis.core.dao.DeptListRedisDAO;

import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.scrm.controller.admin.customer.vo.CustomerAutoUnlockVO;
import cn.iocoder.yudao.module.scrm.controller.admin.customer.vo.customerrepository.*;
import cn.iocoder.yudao.module.scrm.dal.dataobject.customer.customerrepository.CustomerRepositoryDO;
import cn.iocoder.yudao.module.scrm.dal.dataobject.customer.customerrepository.CustomerRepositoryRuleDO;
import cn.iocoder.yudao.module.scrm.dal.mysql.customer.customerrepository.CustomerRepositoryMapper;
import cn.iocoder.yudao.module.scrm.dal.mysql.customer.customerrepository.CustomerRepositoryRuleMapper;

import cn.iocoder.yudao.module.scrm.service.customer.CustomerService;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;

import cn.iocoder.yudao.module.system.api.dept.dto.DeptSimpleDTO;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.scrm.enums.ErrorCodeConstants.*;


/**
 * 客户库 Service 实现类
 *
 * @author admin
 */
@Service
@Validated
public class CustomerRepositoryServiceImpl implements CustomerRepositoryService {

    @Resource
    private CustomerRepositoryMapper customerRepositoryMapper;
    @Resource
    private CustomerRepositoryRuleMapper customerRepositoryRuleMapper;

    @Resource
    private DeptListRedisDAO deptListRedisDAO;

    @Resource
    private DeptApi deptApi;

    @Resource
    private CustomerService customerService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer createCustomerRepository(CustomerRepositorySaveReqVO createReqVO) {
        // 插入
        CustomerRepositoryDO customerRepository = BeanUtils.toBean(createReqVO, CustomerRepositoryDO.class);
        customerRepositoryMapper.insert(customerRepository);

        // 插入子表
        //createCustomerRepositoryRuleList(customerRepository.getId(), createReqVO.getCustomerRepositoryRules());
        // 返回
        return customerRepository.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateCustomerRepository(CustomerRepositorySaveReqVO updateReqVO) {
        // 校验存在
        validateCustomerRepositoryExists(updateReqVO.getId());
        //有子表就不能进行修改
        Optional.ofNullable(getCustomerRepositoryRuleListByCustomerRepositoryId(updateReqVO.getId()))
                .filter(list -> !list.isEmpty())
                .ifPresent(list -> { throw exception(CUSTOMER_REPOSITORY_HAVE_RULE_NOT_UPDATE); });
        // 更新
        CustomerRepositoryDO updateObj = BeanUtils.toBean(updateReqVO, CustomerRepositoryDO.class);
        customerRepositoryMapper.updateById(updateObj);

        // 更新子表
        //updateCustomerRepositoryRuleList(updateReqVO.getId(), updateReqVO.getCustomerRepositoryRules());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteCustomerRepository(Integer id) {
        // 校验存在
        validateCustomerRepositoryExists(id);
        /*//自动解锁符合条件的客户锁定
        customerService.autoUnlockCustomer(CustomerAutoUnlockVO.builder()
                .build().setRepositoryId(id).setType(1).setOperationType(3)
        );*/
        // 删除
        customerRepositoryMapper.deleteById(id);

        // 删除子表
        deleteCustomerRepositoryRuleByCustomerRepositoryId(id);
    }

    private void validateCustomerRepositoryExists(Integer id) {
        if (customerRepositoryMapper.selectById(id) == null) {
            throw exception(CUSTOMER_REPOSITORY_NOT_EXISTS);
        }
    }

    @Override
    public CustomerRepositoryDO getCustomerRepository(Integer id) {
        return customerRepositoryMapper.selectById(id);
    }

    @Override
    public PageResult<CustomerRepositoryDO> getCustomerRepositoryPage(CustomerRepositoryPageReqVO pageReqVO) {
        return customerRepositoryMapper.selectPage(pageReqVO);
    }

    // ==================== 子表（客户库规则） ====================

    @Override
    public List<CustomerRepositoryRuleDO> getCustomerRepositoryRuleListByCustomerRepositoryId(Integer customerRepositoryId) {
        return customerRepositoryRuleMapper.selectListByCustomerRepositoryId(customerRepositoryId);
    }

    /**
     * 获取部门的使用范围
     * @param reqVo 类型和客户库id等信息
     * @return 部门列表
     */
    @Override
    public List<DeptUseScopeByTypeRespVo> deptUseScopeByType(DeptUseScopeByTypeReqVo reqVo) throws JsonProcessingException {
        Long tenantId = TenantContextHolder.getTenantId();
        // 先从 Redis 缓存中获取所有部门信息，如果不存在或为空，则从数据库获取并缓存
        List<DeptSimpleDTO> allSimpleDeptList = Optional.ofNullable(deptListRedisDAO.getDeptListFromCache(tenantId))
                .filter(list -> !list.isEmpty()) // 过滤掉空列表
                .orElseGet(() -> {
                    // 从数据库获取部门信息
                    List<DeptSimpleDTO> deptListFromDB = deptApi.getAllSimpleDeptListNotCheckDataPermission().getCheckedData();
                    try {
                        // 将部门信息缓存到 Redis，并设置过期时间
                        deptListRedisDAO.cacheDeptList(deptListFromDB,tenantId);
                    } catch (JsonProcessingException e) {
                        // 日志记录异常信息（可以使用具体的日志工具）
                        e.printStackTrace();
                    }
                    return deptListFromDB;
                });

        // 根据请求类型选择不同的处理逻辑
        switch (reqVo.getType()) {
            case 0:
                return handleCustomerRepository(reqVo, allSimpleDeptList);
            case 1:
                return handleCustomerRule(reqVo, allSimpleDeptList);
            default:
                throw new IllegalArgumentException("Invalid type from DeptUseScopeByTypeReqVo");
        }
    }

    private List<DeptUseScopeByTypeRespVo> handleCustomerRepository(DeptUseScopeByTypeReqVo reqVo, List<DeptSimpleDTO> allSimpleDeptList) {

        // 根据操作类型执行不同的逻辑
        switch (reqVo.getOperationType()) {
            case 0: // 新增客户库
                return handleNewCustomerRepository(allSimpleDeptList);
            case 1: // 修改客户库
                return handleUpdateCustomerRepository(reqVo, allSimpleDeptList);
            default:
                throw new IllegalArgumentException("Invalid operation type for customer repository from DeptUseScopeByTypeReqVo");
        }
    }

    private List<DeptUseScopeByTypeRespVo> handleNewCustomerRepository(List<DeptSimpleDTO> allSimpleDeptList) {
        List<CustomerRepositoryDO> repositoryList = customerRepositoryMapper.selectList();

        // 如果没有客户库，返回所有部门
        if (repositoryList == null || repositoryList.isEmpty()) {
            return BeanUtils.toBean(allSimpleDeptList, DeptUseScopeByTypeRespVo.class);
        }

        // 获取所有已配置客户库的部门ID集合
        Set<Long> configuredDeptIds = repositoryList.stream()
                .filter(repo -> repo.getDeptIds() != null)
                .flatMap(repo -> repo.getDeptIds().stream())
                .collect(Collectors.toSet());

        // 过滤掉已配置客户库的部门
        List<DeptSimpleDTO> availableDepts = allSimpleDeptList.stream()
                .filter(dept -> !configuredDeptIds.contains(dept.getId()))
                .collect(Collectors.toList());

        return BeanUtils.toBean(availableDepts, DeptUseScopeByTypeRespVo.class);
    }

    private List<DeptUseScopeByTypeRespVo> handleUpdateCustomerRepository(DeptUseScopeByTypeReqVo reqVo, List<DeptSimpleDTO> allSimpleDeptList) {

        // 获取当前客户库的信息
        CustomerRepositoryDO customerRepositoryDO = customerRepositoryMapper.selectById(reqVo.getRepositoryId());

        // 获取当前客户库的部门ID集合
        List<Long> currentDeptIds = customerRepositoryDO.getDeptIds();

        // 获取所有已配置客户库的部门ID集合（排除当前正在修改的客户库）
        Set<Long> otherConfiguredDeptIds = customerRepositoryMapper.selectList().stream()
                .filter(repo -> !repo.getId().equals(reqVo.getRepositoryId())) // 排除当前客户库
                .filter(repo -> repo.getDeptIds() != null)
                .flatMap(repo -> repo.getDeptIds().stream())
                .collect(Collectors.toSet());

        // 可用部门 = 当前客户库的部门 + 未被其他客户库使用的部门
        List<DeptSimpleDTO> availableDepts = allSimpleDeptList.stream()
                .filter(dept -> currentDeptIds.contains(dept.getId()) || !otherConfiguredDeptIds.contains(dept.getId()))
                .collect(Collectors.toList());

        return BeanUtils.toBean(availableDepts, DeptUseScopeByTypeRespVo.class);
    }

    private List<DeptUseScopeByTypeRespVo> handleCustomerRule(DeptUseScopeByTypeReqVo reqVo, List<DeptSimpleDTO> allSimpleDeptList) {
        // 根据操作类型执行不同的逻辑
        switch (reqVo.getOperationType()) {
            case 0: // 新增规则
                return handleNewCustomerRule(reqVo, allSimpleDeptList);
            case 1: // 修改规则
                return handleUpdateCustomerRule(reqVo, allSimpleDeptList);
            default:
                throw new IllegalArgumentException("Invalid operation type for customer rule");
        }
    }

    /**
     * 处理新增规则的逻辑
     * @param reqVo 请求参数
     * @param allSimpleDeptList 所有部门列表
     * @return 可选择的部门范围列表
     */
    private List<DeptUseScopeByTypeRespVo> handleNewCustomerRule(DeptUseScopeByTypeReqVo reqVo, List<DeptSimpleDTO> allSimpleDeptList) {
        // 查询当前仓库
        CustomerRepositoryDO customerRepositoryDO = customerRepositoryMapper.selectById(reqVo.getRepositoryId());
        if (customerRepositoryDO == null) {
            throw exception(CUSTOMER_REPOSITORY_NOT_EXISTS); // 仓库未找到异常
        }

        // 获取仓库关联的部门
        List<Long> repositoryDeptIds = customerRepositoryDO.getDeptIds();

        // 如果仓库未配置部门，抛出提示
        if (repositoryDeptIds == null || repositoryDeptIds.isEmpty()) {
            throw exception(CUSTOMER_REPOSITORY_CONFIG_DEPT_SCOPE); // 仓库未配置部门异常
        }

        // 查询当前仓库中是否存在其他规则
        List<CustomerRepositoryRuleDO> ruleDOList = customerRepositoryRuleMapper
                .selectList(CustomerRepositoryRuleDO::getCustomerRepositoryId, reqVo.getRepositoryId());

        // 已使用的部门列表
        Set<Long> usedDeptIds = ruleDOList.stream()
                .flatMap(rule -> rule.getDeptIds().stream()) // 提取每条规则已使用的部门
                .collect(Collectors.toSet()); // 收集已使用的部门

        // 计算剩余的可用部门 = 仓库的部门 - 已使用的部门
        List<Long> availableDeptIds = repositoryDeptIds.stream()
                .filter(deptId -> !usedDeptIds.contains(deptId)) // 过滤掉已使用的部门
                .collect(Collectors.toList());

        // 如果没有剩余部门可选，抛出异常
        if (availableDeptIds.isEmpty()) {
            throw exception(CUSTOMER_REPOSITORY_ALL_DEPTS_USED); // 所有部门都已被规则占用
        }

        // 转换为需要的响应格式
        return convertToDeptUseScopeByTypeRespVo(availableDeptIds, allSimpleDeptList);
    }

    /**
     * 转换部门ID列表为响应的DeptUseScopeByTypeRespVo对象
     * @param deptIds 部门ID列表
     * @param allSimpleDeptList 所有部门列表
     * @return 转换后的响应列表
     */
    private List<DeptUseScopeByTypeRespVo> convertToDeptUseScopeByTypeRespVo(List<Long> deptIds, List<DeptSimpleDTO> allSimpleDeptList) {
        // 通过部门ID列表匹配部门详情并转换为响应对象
        return allSimpleDeptList.stream()
                .filter(dept -> deptIds.contains(dept.getId())) // 过滤出匹配的部门
                .map(dept -> new DeptUseScopeByTypeRespVo(dept.getId(), dept.getName(),dept.getParentId())) // 转换为响应对象
                .collect(Collectors.toList());
    }


    /**
     * 处理修改规则的逻辑
     * @param reqVo 请求参数
     * @param allSimpleDeptList 所有部门列表
     * @return 可选择的部门范围列表
     */
    private List<DeptUseScopeByTypeRespVo> handleUpdateCustomerRule(DeptUseScopeByTypeReqVo reqVo, List<DeptSimpleDTO> allSimpleDeptList) {
        // 查询当前仓库
        CustomerRepositoryDO customerRepositoryDO = customerRepositoryMapper.selectById(reqVo.getRepositoryId());
        if (customerRepositoryDO == null) {
            throw exception(CUSTOMER_REPOSITORY_NOT_EXISTS); // 仓库未找到异常
        }

        // 获取当前仓库的部门
        List<Long> repositoryDeptIds = customerRepositoryDO.getDeptIds();

        // 查询当前规则和之前已使用的部门
        CustomerRepositoryRuleDO currentRule = customerRepositoryRuleMapper.selectById(reqVo.getRepositoryRuleId());
        List<Long> currentRuleDeptIds = currentRule.getDeptIds();

        // 查询其他规则，并获取其使用的部门范围
        List<CustomerRepositoryRuleDO> otherRules = customerRepositoryRuleMapper
                .selectList( CustomerRepositoryRuleDO::getCustomerRepositoryId, reqVo.getRepositoryId());

        // 已使用的部门（不包括当前规则的部门）
        Set<Long> usedDeptIds = otherRules.stream()
                .flatMap(rule -> rule.getDeptIds().stream())
                .collect(Collectors.toSet());

        // 可选的部门范围 = 仓库的部门 - 其他规则的部门 + 当前规则之前使用的部门
        List<Long> availableDeptIds = repositoryDeptIds.stream()
                .filter(deptId -> !usedDeptIds.contains(deptId) || currentRuleDeptIds.contains(deptId))
                .collect(Collectors.toList());

        // 转换为响应对象
        return convertToDeptUseScopeByTypeRespVo(availableDeptIds, allSimpleDeptList);
    }





    private void createCustomerRepositoryRuleList(Integer customerRepositoryId, List<CustomerRepositoryRuleDO> list) {
        list.forEach(o -> o.setCustomerRepositoryId(customerRepositoryId));
        customerRepositoryRuleMapper.insertBatch(list);
    }

    private void updateCustomerRepositoryRuleList(Integer customerRepositoryId, List<CustomerRepositoryRuleDO> list) {
        deleteCustomerRepositoryRuleByCustomerRepositoryId(customerRepositoryId);
		list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下：1）id 冲突；2）updateTime 不更新
        createCustomerRepositoryRuleList(customerRepositoryId, list);
    }

    private void deleteCustomerRepositoryRuleByCustomerRepositoryId(Integer customerRepositoryId) {
        customerRepositoryRuleMapper.deleteByCustomerRepositoryId(customerRepositoryId);
    }

}